package com.itheima.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.mapper.DishMapper;
import com.itheima.reggie.service.IDishService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.Key;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜品管理 服务实现类
 * </p>
 *
 * @author
 * @since 2024-05-22
 */
@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements IDishService {

    @Autowired
    public RedisTemplate redisTemplate;

    @Override
    public R<Page> pageQuery(Integer page, Integer pageSize, String name) {

        Page<Dish> dishPage = new Page<>(page, pageSize);
        Page<DishDto> dishDtoPage = new Page<>();
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<Dish>()
                .like(name != null, Dish::getName, name)
                .orderByDesc(Dish::getUpdateTime);
        Page<Dish> p = page(dishPage, wrapper);

        //从元分页查询结果返回对象获取分页查询的数据集合
        List<Dish> dishes = dishPage.getRecords();
        //stream流处理集合数据从 List<Dish> dishes转化为 List<DishDto> DishDtos
        List<DishDto> dishDtos = dishes.stream().map((dish) -> {
            Long categoryId = dish.getCategoryId();
            Category category = Db.lambdaQuery(Category.class).eq(Category::getId, categoryId).one();
            String categoryName = category.getName();
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(dish, dishDto);
            dishDto.setCategoryName(categoryName);
            return dishDto;
        }).collect(Collectors.toList());
        /**
         * springframework提供的工具用以对象拷贝
         * copyProperties()方法的第三个参数来忽略某一项属性的拷贝 "ignoreProperties"
         * 这里忽略拷贝原先分页查询的记录数据集合List<Dish> records
         */
        BeanUtils.copyProperties(dishPage, dishDtoPage, "records");
        dishDtoPage.setRecords(dishDtos);


        return R.success(dishDtoPage);
    }

    @Override
    @Transactional
    public R<String>    saveDishAndDishFlavor(DishDto dishDto) {
        //设置key名称
        Long categoryId = dishDto.getCategoryId();
        String key = "dish_" + categoryId + "_1";
        //1.添加的菜品存入到菜品表中
        saveOrUpdate(dishDto);
        //2.添加口味到菜品口味表中
        /**
         * 注意:save(dishDto)存入表中后,Mybatis默认给每个菜品进行主键id赋值,没有指定方式默认雪花算法产生
         * 并且id存入表后,主键id值会回显到dishDto对象内
         */
        Long dishId = dishDto.getId();
        log.info("菜品id为:{}", dishId);
        List<DishFlavor> flavors = dishDto.getFlavors();
        //2.1判断DishFlavor对应的表中字段 dish_id 属性值等于dishId,如果存在则删除dish_id字段内值为dishId的记录
        List<DishFlavor> dishFlavors = Db.lambdaQuery(DishFlavor.class).eq(DishFlavor::getDishId, dishId).list();

        if (!dishFlavors.isEmpty()) {
            List<Long> dishFlavorsIds = dishFlavors.stream().map(dishFlavor -> {
                return dishFlavor.getId();
            }).collect(Collectors.toList());
            //表时存在字段dish_id值为dish_id的记录,进行记录删除
            Db.removeByIds(dishFlavorsIds, DishFlavor.class);
        }
        //2.2如果添加的口味数据集合不为空,则为集合内的每个DishFlavor对象添加dishId
        List<DishFlavor> list = null;
        if (!flavors.isEmpty()) {
            list = flavors.stream().map(dishDtoFlavor -> {
                dishDtoFlavor.setDishId(dishId);
                return dishDtoFlavor;
            }).collect(Collectors.toList());
            //2.3Db静态工具存储List<DishFlavor>集合到表中 注意:因为saveBatch提供的新增对象已经指定了类型,所以静态工具无需再指定类型
            Db.save(list);
        }

        //清理缓存
        redisTemplate.delete(key);
        return R.success("菜品添加成功!");
    }

    @Override
    public R<DishDto> queryDishAndDishFlavorById(Long id) {
        Dish dish = getById(id);
        List<DishFlavor> dishFlavors = Db.lambdaQuery(DishFlavor.class).eq(DishFlavor::getDishId, id).list();
        DishDto dishDto = new DishDto();
        //拷贝数据 dish-> dishDto
        BeanUtils.copyProperties(dish, dishDto);
        dishDto.setFlavors(dishFlavors);
        return R.success(dishDto);
    }

    @Override
    public R<List<DishDto>> queryByCategoryIdAndStatus(Long categoryId, Integer status) {
        List<DishDto> dishDtoList = null;

        ValueOperations valueOperations = redisTemplate.opsForValue();

        //1.创建一个动态的Key
        String key = "dish_" + categoryId + "_" + status;

        //2.通过key查询redis内的对应value值
        dishDtoList = (List<DishDto>) valueOperations.get(key);

        //3.判断value值是否有数据,有直接返回
        if (dishDtoList != null) {
            return R.success(dishDtoList);
        }

        //4.如果value值为空,则查询数据库
        List<Dish> dishes = lambdaQuery()
                .eq(Dish::getCategoryId, categoryId)
                .eq(Dish::getStatus, 1)
                .orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime)
                .list();
        dishDtoList = dishes.stream().map(dish -> {
            Long dishId = dish.getId();
            DishDto dishDto = new DishDto();
            List<DishFlavor> dishFlavorList = Db.lambdaQuery(DishFlavor.class)
                    .eq(DishFlavor::getDishId, dishId)
                    .list();
            dishDto.setFlavors(dishFlavorList);
            BeanUtils.copyProperties(dish, dishDto);
            return dishDto;
        }).collect(Collectors.toList());
        //4.1将从数据库内查询到的结果 存一份到key的值中(存储时限是60分钟)
        valueOperations.set(key, dishDtoList, 60, TimeUnit.MINUTES);

        return R.success(dishDtoList);
    }

    @Override
    @Transactional
    public R<String> delete(List<Long> ids) {

        //1.根据id删除菜品数据
        removeByIds(ids);

        //2.根据菜品id删除口味表里对应的数据
        List<DishFlavor> dishFlavors = Db.lambdaQuery(DishFlavor.class)
                .in(DishFlavor::getDishId, ids)
                .list();
        if (dishFlavors.isEmpty()) {
            //进行redis缓存删除
            Set keys = redisTemplate.keys("dish_*"); //通配符来查找名称带有dish_的key
            redisTemplate.delete(keys); //可以删一个也可以删多个
            return R.success("删除成功");
        }

        List<Long> dishFlavorIds = dishFlavors.stream().map(dishFlavor -> {
            return dishFlavor.getId();
        }).collect(Collectors.toList());

        Db.removeByIds(dishFlavorIds, DishFlavor.class);

        //进行redis缓存删除
        Set keys = redisTemplate.keys("dish_*"); //通配符来查找名称带有dish_的key
        redisTemplate.delete(keys); //可以删一个也可以删多个
        return R.success("删除成功");
    }
}
